# Picasa Editor - A componnet of uimain.py
#
# Copyright (C) 2010 Yotam Medini <yotam.medini@gmail.com>
#
# This file is part of Gupicasa.
#
# Gupicasa is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Gupicasa is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gupicasa.  If not, see <http://www.gnu.org/licenses/>.


import gtk

# local
import albums
import debug
import lru
import mosaic
import rect
import ugtk


(
    ALBUM_ITEM_NORMAL,
    ALBUM_ITEM_SELECT_LABEL,
    ALBUM_ITEM_SELECT_DIALOG
) = range(3)


class PixBufGetter:


    def __init__(self, pixbuf_get, gis):
        self.pixbuf_get = pixbuf_get
        self.gis = gis
        self.i = 0


    def step(self):
        status_text = None
        i = self.i
        n = len(self.gis)
        if i < n:
            pixbuf = self.pixbuf_get(i)
            if pixbuf is not None:
                self.gis[i].set_from_pixbuf(pixbuf)
            i += 1
            status_text = "%d of %d images loaded" % (i, n)
            self.i = i
        return status_text


class PicasaEditor:


    def __init__(self, uimain):
        debug.log("uimain=%s, parent=%s" % (uimain, uimain.parent))
        uimain.common.preferences.observers.append(self.prefs_observer)
        cmdbox = uimain.picasa_control_frame.get_child()
        self.uimain = uimain
        self.current_album_id = None
        self.scale2fit = True
        self.photos_info = []
        self.current_photo_index = -1
        self.pixbufs_cache = lru.Cache()
        self.pixbufs_scaled_cache = lru.Cache()
        self.mainwin = self.create_gui(cmdbox)
        self.mainwin.show_all()
        self.add_box_commands()
        self.create_album_selector()
        cmdbox.pack_start(self.label_n_selected, expand=False, fill=True,
                          padding=2)


    def create_gui(self, cmdbox):
        pane = gtk.VPaned()
        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        nzc = self.uimain.common.preferences.mosaic_zcolumns()
        self.label_n_selected = gtk.Label("")
        self.tbl_mosaic = mosaic.Mosaic(nzc, self.label_n_selected)
        sw.add_with_viewport(self.tbl_mosaic)
        pane.pack1(sw, resize=True, shrink=True)
        pane.pack2(self.create_detailed_window(), resize=True, shrink=True)
        pane.show_all()
        ugtk.add_fit_native_zoom_control(cmdbox, self.set_zoom_mode)
        return pane


    def create_detailed_window(self):
        vbox = gtk.VBox()
        hbox = gtk.HBox()
        hbox.pack_start(gtk.Label("Caption:"), expand=False, fill=False,
                                  padding=6)
        self.detailed_caption = e = gtk.Entry()
        e.set_editable(False)
        hbox.pack_start(e, expand=True, fill=True, padding=6)
        vbox.pack_start(hbox, expand=False, fill=False, padding=2)
        self.detailed_info = gtk.Label()
        vbox.pack_start(self.detailed_info, expand=False, fill=False, padding=2)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.detailed_img = gtk.Image()
        sw.add_with_viewport(self.detailed_img)
        vbox.pack_start(sw, expand=True, fill=True, padding=4)

        return vbox


    def control_box(self):
        return self.uimain.picasa_control_frame.get_child()


    def add_box_commands(self):
        box = self.control_box()

        b = ugtk.StockButton(gtk.STOCK_REFRESH)
        b.connect('clicked', self.reload_album)
        b.set_tooltip_text("Reopen current Picasa album")
        box.pack_start(b, expand=False, fill=False, padding=2)

        b = ugtk.StockButton(gtk.STOCK_REMOVE)
        b.connect('clicked', self.delete_photos)
        b.set_tooltip_text("Delete selected photos\n"
                           "from current Picasa album")
        box.pack_start(b, expand=False, fill=False, padding=2)


    def create_album_selector(self):
        debug.log("")
        albums = gtk.ListStore(str, str, int)
        self.albums_combo = combobox = gtk.ComboBox(albums)
        self.albums_combo.set_tooltip_text("Select Picasa album\n" +
                                           "while connected")
        cell = gtk.CellRendererText()
        combobox.pack_start(cell)
        combobox.add_attribute(cell, 'text', 0)
        self.albums_combo.show_all()
        self.album_changed_handler = None
        self.uimain.connect_time_widgets.append(combobox)
        self.control_box().pack_start(combobox,
                                      expand=False, fill=False, padding=1)


    def set_albums_menu(self):
        debug.log("")
        if self.album_changed_handler is not None:
            # Changes made here, should not get callbacks
            self.albums_combo.disconnect(self.album_changed_handler)
            self.album_changed_handler = None
        albums_info = self.uimain.parent.get_albums_info()
        debug.log("#albums=%d" % len(albums_info))
        model = self.albums_combo.get_model()
        model.clear()
        if self.current_album_id is not None:
            aii = 0
            while len(model) == 0 and aii < len(albums_info):
                ai = albums_info[aii]
                if self.current_album_id == ai.id:
                    model.append(["%s" % (ai.name), ai.id, ALBUM_ITEM_NORMAL])
                aii += 1
            if len(model) == 0: 
                debug.log("Error, album id=%s disappeared" % 
                          self.current_album_id)
                self.current_album_id = None
        if self.current_album_id == None:
            model.append(["Select Album", "", ALBUM_ITEM_SELECT_LABEL])
        for ai in albums_info[:20]:
            if ai.id != self.current_album_id: # not already added
                model.append(["%s" % (ai.name), ai.id, ALBUM_ITEM_NORMAL])
        model.append(["Other/Create...", "", ALBUM_ITEM_SELECT_DIALOG])
        self.albums_combo.set_active(0) # 'Select' or <current>
        self.album_changed_handler = self.albums_combo.connect(
            'changed', self.album_select)


    def thumb_pixbuf(self, i):
        photo_info = self.photos_info[i]
        thumb_data = photo_info.get_thumb_image()
        return ugtk.image_data_to_pixbuf(thumb_data)


    def set_current_album_photos(self):
        debug.log("")
        self.photos_info = self.uimain.parent.get_photos_info(
            self.current_album_id)
        n=len(self.photos_info)
        self.status_set_text("Setting %d Picasa photos ..." % n)
        gis = self.tbl_mosaic.place_images(n, pick=self.pick_detailed)
        pbg = PixBufGetter(self.thumb_pixbuf, gis)
        monitor = ugtk.Monitor(title="Getting thumb images from Picasa",
                               parent=self.uimain.topwin,
                               step_cb=pbg.step,
                               status_widgets=[self.uimain.common.statusbar])
        done = monitor.run_monitor()
        monitor.destroy()
        if done:
            if n == 0:
                self.empty_detailed()
            for i in range(n):
                tip = self.photos_info[i].get_caption_text()
                if tip != "":
                    gis[i].set_tooltip_text(tip)
            self.status_set_text("Picasa album has %d photos" % n)
        else:
            self.status_set_text("Picasa thumbs loading canceled")


    def draw_detailed_photo(self):
        debug.log("")
        if self.current_photo_index >= 0:
            pi = self.photos_info[self.current_photo_index]
            pixbuf = self.pixbufs_cache.get(pi.url)
            if pixbuf is None:
                pixbuf = ugtk.image_data_to_pixbuf(pi.get_image())
                debug.log("pixbuf=%s" % pixbuf)
                self.pixbufs_cache.set(pi.url, pixbuf)
            if pixbuf is not None:
                wimg = self.detailed_img
                if self.scale2fit:
                    pixbuf = self.get_fit_pixbuf(
                        pixbuf, wimg.get_parent().get_window(), pi)
                wimg.set_from_pixbuf(pixbuf)
                wimg.show()


    def empty_detailed(self):
        debug.log("")
        self.detailed_img.clear()
        map(lambda w: w.set_text(""), 
            [self.detailed_caption, self.detailed_info])


    def get_fit_pixbuf(self, pixbuf, win, photo_info):
        debug.log("")
        if win is not None:
            piwh = (photo_info.width, photo_info.height)
            wh = rect.scale_to_fit(piwh, win.get_size())
            key = (wh, photo_info.url)
            pb = self.pixbufs_scaled_cache.get(key)
            if pb is None:
                debug.log("scale: piwh=%s, wh=%s:" % (str(piwh), str(wh)))
                pixbuf = pixbuf.scale_simple(wh[0], wh[1], gtk.gdk.INTERP_TILES)
                self.pixbufs_scaled_cache.set(key, pixbuf)
            else:
                pixbuf = pb
        return pixbuf


    def on_focus(self, on):
        debug.log("uimain=%s" % self.uimain)
        if on:
            self.update_status()


    def update_status(self):
        debug.log("uimain=%s" % self.uimain)
        gupicasa = self.uimain.parent
        msg = ""
        if gupicasa is not None:
            if gupicasa.service is not None:
                if self.current_album_id is None:
                    msg = "Please select Album"
            else:
                msg = "Please connect to Picasa"
        self.status_set_text(msg)


    def status_set_text(self, msg):
        self.uimain.common.statusbar.set_text(msg)


    #############
    # Callbacks #

    def album_select(self, combobox):
        debug.log("")
        model = combobox.get_model()
        index = combobox.get_active()
        item_type = model[index][2] if index >= 0 else -1
        debug.log("index=%d, item_type=%d" % (index, item_type))
        if item_type in (ALBUM_ITEM_NORMAL, ALBUM_ITEM_SELECT_DIALOG):
            if item_type == ALBUM_ITEM_NORMAL:
                debug.log("e=[%s, %s]" % (model[index][0], model[index][1]))
                aid = model[index][1]
            else: # item_type == ALBUM_ITEM_SELECT_DIALOG:
                debug.log("Select/Create")
                ae = albums.AlbumsEditor(self)
                aid = ae.select() # also destroys the AlbumsEditor
                debug.log("aid=%s" % aid)
            if (not aid in ("", self.current_album_id)) and aid is not None:
                self.current_album_id = aid
                self.set_current_album_photos()
            self.set_albums_menu()


    def reload_album(self, w):
        debug.log("")
        if self.current_album_id is not None:
            self.set_current_album_photos()


    def pick_detailed(self, w, i):
        debug.log("w=%s, i=%d  active=%d, mode=%d" %
                  (w, i, w.get_active(), w.get_mode()))
        self.current_photo_index = i
        pi = self.photos_info[i]
        self.detailed_caption.set_text(pi.get_caption_text())
        self.detailed_info.set_markup(
             ("<b>Geometry:</b> %dx%d  " +
              "<b>Size:</b> %d bytes   " +
              "<b>Time:</b> %s") %
             (pi.width, pi.height, pi.size, pi.epoch_to_ymd_hms()))
        self.draw_detailed_photo()


    def set_zoom_mode(self, fit_flag, dummy):
        debug.log("fit_flag=%d" % fit_flag)
        self.scale2fit = fit_flag
        self.draw_detailed_photo()


    def delete_photos(self, w):
        debug.log("")
        si = self.tbl_mosaic.selected_indices
        do_del = self.uimain.confirm("""
You are about to delete
%d photos from the current
Picasa album
"""[1:] % len(si))
        debug.log("do_del=%d" % do_del)
        if do_del:
            gupicasa = self.uimain.parent
            for pi in si:
                photo_info = self.photos_info[pi]
                debug.log("photo_id=%s" % photo_info.photo_id)
                gupicasa.del_photo(self.current_album_id, photo_info.photo_id)
            self.set_current_album_photos()


    def prefs_observer(self, prefs):
        debug.log("")
        self.tbl_mosaic.n_columns = prefs.mosaic_zcolumns()
